package cn.itrigger.dynamic.sql;

import cn.itrigger.dynamic.sql.condition.VisitableCondition;
import cn.itrigger.dynamic.sql.structure.BindableColumn;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Stream;

/**
 * sql判断条件
 * @author admin
 * @date 2018/9/21
 **/
public class SqlCriterion<T> {

    private BindableColumn<T> column;

    private VisitableCondition<T> condition;

    private String connector;

    /**
     * 可能多个条件组成一个条件
     */
    private List<SqlCriterion<?>> subCriteria;

    protected SqlCriterion(Builder builder) {
        this.column = Objects.requireNonNull(builder.column);
        this.condition = Objects.requireNonNull(builder.condition);
        this.connector = builder.connector;
        this.subCriteria = Objects.requireNonNull(builder.subCriteria);
    }

    public Optional<String> connector() {
        return Optional.ofNullable(this.connector);
    }

    public BindableColumn<T> getColumn() {
        return column;
    }

    public VisitableCondition<T> getCondition() {
        return condition;
    }

    public <R> Stream<R> mapSubCriteria(Function<SqlCriterion<?>,R> mapper) {
        return subCriteria.stream().map(mapper);
    }

    public static <T> Builder<T> withColumn(BindableColumn<T> column) {
        return new Builder<T>().withColumn(column);
    }

    public static class Builder<T> {
        private String connector;
        private BindableColumn<T> column;
        private VisitableCondition<T> condition;
        private List<SqlCriterion<?>> subCriteria = new ArrayList<>();

        public Builder<T> withConnector(String connector) {
            this.connector = connector;
            return this;
        }

        public Builder<T> withColumn(BindableColumn<T> column) {
            this.column = column;
            return this;
        }

        public Builder<T> withCondition(VisitableCondition<T> condition) {
            this.condition = condition;
            return this;
        }

        public Builder<T> withSubCriteria(List<SqlCriterion<?>> subCriteria) {
            this.subCriteria = subCriteria;
            return this;
        }

        public SqlCriterion<T> build() {
            return new SqlCriterion<>(this);
        }
    }
}
